﻿// Project: Salient
// http://salient.codeplex.com
// 
// Copyright 2010, Sky Sanders <sky at skysanders.net>
// licensed under the GPL Version 2 licenses.
// http://salient.codeplex.com/license
// 
// 
// You may use this code under the terms of the GNU General Public 
// License (GPL) Version 2.
using System;
using System.Threading;

namespace Salient.Net
{
    ///<summary>
    ///</summary>
    ///<typeparam name = "T"></typeparam>
    public class GatewayAsyncResult<T> : IAsyncResult, IDisposable
        where T : class, new()
    {
        private readonly object _asyncState;
        private readonly GatewayAsyncCallback<T> _callback;
        private readonly object _syncRoot;
        private readonly ManualResetEvent _waitHandle;
        private bool _completed;
        private bool _completedSynchronously;
        private Exception _e;
        private T _result;


        ///<summary>
        ///</summary>
        ///<param name = "cb"></param>
        ///<param name = "state"></param>
        public GatewayAsyncResult(GatewayAsyncCallback<T> cb, object state)
            : this(cb, state, false)
        {
        }

        ///<summary>
        ///</summary>
        ///<param name = "cb"></param>
        ///<param name = "state"></param>
        ///<param name = "completed"></param>
        public GatewayAsyncResult(GatewayAsyncCallback<T> cb, object state, bool completed)
        {
            _callback = cb;
            _asyncState = state;
            _completed = completed;
            _completedSynchronously = completed;
            _syncRoot = new object();
            _waitHandle = new ManualResetEvent(false);
        }

        ///<summary>
        ///</summary>
        public Exception Exception
        {
            get
            {
                lock (_syncRoot)
                {
                    return _e;
                }
            }
        }

        /// <summary>
        /// </summary>
        public T Result
        {
            get
            {
                lock (_syncRoot)
                {
                    return _result;
                }
            }
        }

        #region IAsyncResult Members

        /// <summary>
        ///   Gets a user-defined object that qualifies or contains information about an asynchronous operation.
        /// </summary>
        /// <returns>
        ///   A user-defined object that qualifies or contains information about an asynchronous operation.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public object AsyncState
        {
            get { return _asyncState; }
        }

        /// <summary>
        ///   Gets a <see cref = "T:System.Threading.WaitHandle" /> that is used to wait for an asynchronous operation to complete.
        /// </summary>
        /// <returns>
        ///   A <see cref = "T:System.Threading.WaitHandle" /> that is used to wait for an asynchronous operation to complete.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public WaitHandle AsyncWaitHandle
        {
            get { return _waitHandle; }
        }

        /// <summary>
        ///   Gets a value that indicates whether the asynchronous operation completed synchronously.
        /// </summary>
        /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public bool CompletedSynchronously
        {
            get
            {
                lock (_syncRoot)
                {
                    return _completedSynchronously;
                }
            }
        }

        /// <summary>
        ///   Gets a value that indicates whether the asynchronous operation has completed.
        /// </summary>
        /// <returns>true if the operation is complete; otherwise, false.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public bool IsCompleted
        {
            get
            {
                lock (_syncRoot)
                {
                    return _completed;
                }
            }
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        ///   Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        /// <summary>
        /// </summary>
        /// <param name = "result"></param>
        /// <param name = "completedSynchronously"></param>
        public void Complete(T result, bool completedSynchronously)
        {
            lock (_syncRoot)
            {
                _completed = true;
                _completedSynchronously = completedSynchronously;
                _result = result;
            }

            SignalCompletion();
        }

        /// <summary>
        /// </summary>
        /// <param name = "e"></param>
        /// <param name = "completedSynchronously"></param>
        public void HandleException(Exception e, bool completedSynchronously)
        {
            lock (_syncRoot)
            {
                _completed = true;
                _completedSynchronously = completedSynchronously;
                _e = e;
            }

            SignalCompletion();
        }


        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                lock (_syncRoot)
                {
                    if (_waitHandle != null)
                    {
                        ((IDisposable) _waitHandle).Dispose();
                    }
                }
            }
        }

        private void SignalCompletion()
        {
            if (_waitHandle != null)
            {
                _waitHandle.Set();
            }

            ThreadPool.QueueUserWorkItem(InvokeCallback);
        }

        private void InvokeCallback(object ignored)
        {
            if (_callback != null)
            {
                _callback(this);
            }
        }
    }
}
